#pragma once

#include <vector>
#include <queue>
#include <functional>
#include <pthread.h>
#include "Thread.hpp"
#include "LockGuard.hpp"
#include "Log.hpp"

const int defaultthreadnum = 5;

class ThreadData
{
public:
    ThreadData(const std::string name)
        : _threadname(name)
    {
    }

public:
    std::string _threadname;
};

template <class T>
class ThreadPool
{

private:
    ThreadPool(int num = defaultthreadnum)
        : _thread_num(num)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
        for (int i = 0; i < num; i++)
        {
            std::string threadname = "thread - ";
            threadname += std::to_string(i + 1);

            ThreadData td(threadname);
            Thread<ThreadData> t(threadname, std::bind(&ThreadPool<T>::ThreadRun, this, std::placeholders::_1), td);

            _threads.push_back(t);
        }
    }

    ThreadPool(const ThreadPool &t) = delete;
    void operator=(const ThreadPool &t) = delete;

public:
    static ThreadPool<T> *GetInstance()
    {
        if (instance == nullptr)
        {
            LockGuard lockguard(&sig_lock); // 申请不成功就会阻塞，不能立即返回，所以加双if提升效率
            if (instance == nullptr)
            {
                instance = new ThreadPool<T>();
                lg(Info, "单例创建成功。。。。\n");
            }
        }

        return instance;
    }

    // todo
    //  void checkSelf()
    //  {
    //      // lg(Fatal, "进入---");
    //      LockGuard lockguard(&_mutex);
    //      // 扩容
    //      if (_q.size() > _task_num_high_water && _thread_num < _thread_num_high_water)

    //     {
    //         sleep(5);
    //         lg(Fatal, "add thraed");
    //         std::string threadname = "thread - ";
    //         threadname += std::to_string(_threads.size() + 1);

    //         ThreadData td(threadname);
    //         Thread<ThreadData> t(threadname, std::bind(&ThreadPool<T>::ThreadRun, this, std::placeholders::_1), td);
    //         _threads.push_back(t);
    //         t.Start();
    //         _thread_num++;
    //     }
    //     // 缩容
    //     if (_q.size() == _task_num_low_water && _thread_num >= _thread_num_high_water)

    //     {
    //         sleep(10);
    //         lg(Fatal, "-- thraed");
    //         pthread_cancel(_threads[_thread_num - 1].GetId());
    //         _threads.back().Join();
    //         _threads.pop_back();
    //         _thread_num--;
    //     }
    // }

    void Start()
    {
        for (int i = 0; i < _thread_num; i++)
        {
            _threads[i].Start();
            lg(Debug, "thread start thread name : %s \n", _threads[i].ThreadName().c_str());
        }
    }

    void Push(const T &in)
    {
        // checkSelf();
        LockGuard lockguard(&_mutex);
        _q.push(in);
        ThreadWakeUp();
    }

    // 封装一下cond
    void ThreadWait(ThreadData &td)
    {
        pthread_cond_wait(&_cond, &_mutex);
        lg(Debug, "waitthread : %s\n", td._threadname.c_str());
    }

    void ThreadWakeUp()
    {
        pthread_cond_signal(&_cond);
    }

    void ThreadRun(ThreadData &td)
    {
        while (true)
        {
            // std::cout << "runing done ..." << std::endl;
            // sleep(1);
            T t;
            {
                LockGuard lockguard(&_mutex);
                while (_q.empty())
                {
                    ThreadWait(td);
                }
                // 一定有任务
                t = _q.front();
                _q.pop();
                // checkSelf();
            }
            t();  //运行转发方法，将消息转发到所有客服端
            // lg(Info, "Task done : %s   thread name : \n", t.PrintResult().c_str(), td._threadname.c_str());

            // pthread_testcancel(); //设置检查点
            // std::cout << "runing done : " << t.PrintResult() << std::endl;
        }
    }

    void Wait()
    {
        for (int i = 0; i < _thread_num; i++)
        {
            _threads[i].Join();
            lg(Debug, "wait thread thread name : %s \n", _threads[i].ThreadName().c_str());
        }
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

private:
    std::vector<Thread<ThreadData>> _threads;
    std::queue<T> _q;

    int _thread_num;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;

    static pthread_mutex_t sig_lock; // 单例锁
    static ThreadPool<T> *instance;

    ///////////////////////////////
    int _thread_num_low_water = 5;   // 3
    int _thread_num_high_water = 15; // 10
    int _task_num_low_water = 0;     // 0
    int _task_num_high_water = 30;   // 30
};

template <class T>
ThreadPool<T> *ThreadPool<T>::instance = nullptr;

template <class T>
pthread_mutex_t ThreadPool<T>::sig_lock = PTHREAD_MUTEX_INITIALIZER;
